#include "xml_json.hpp"
#include "utils/tinyxml2.h"

using namespace tinyxml2;
using namespace std;

static inline bool is_xml_arr(XMLElement* ele);
static inline void xml_obj(XMLElement* ele, json& data, std::set<std::string> &arr_name);
static inline void xml_arr(XMLElement* ele, json& data);



inline bool is_xml_arr(XMLElement* ele)
{
	XMLElement* child = ele->FirstChildElement();

	vector<string> title_vec;
	string title;
	while (child)
	{
		title = child->Name();
		title_vec.push_back(title);
		child = child->NextSiblingElement();
	}
	if (title_vec.size() > 1) {

		for (auto it : title_vec)
		{
			if (it != title) {
				return false;
			}
		}
		return true;
	}
	else {
		return false;
	}
}

inline void xml_obj(XMLElement* ele, json& data, std::set<std::string>& arr_name)
{
	while (ele)
	{
		const char* title = ele->Name();
		const char* value = ele->GetText();
		

		
		
		if (value != NULL)
		{
			data[title] = value;
		}
		else
		{
			XMLElement* child = ele->FirstChildElement();
			if (child) {
				if (arr_name.count(title) || is_xml_arr(ele)) {
					data[title]["data_list"] = json::array();
					xml_arr(child, data[title]["data_list"]);
				}
				else {
					data[title] = json::object();
					xml_obj(child, data[title], arr_name);

				}
			}
		}
		const XMLAttribute* attirbute = ele->FirstAttribute();
		while (attirbute != NULL)
		{
			data[title][attirbute->Name()] = attirbute->Value();
			attirbute = attirbute->Next();
		}

		ele = ele->NextSiblingElement();
	}
}

inline void xml_arr(XMLElement* ele, json& data)
{
	std::set<std::string> arr_name;
	while (ele)
	{
		json row;
		const char* title = ele->Name();
		const char* value = ele->GetText();
		if (value != NULL)
		{
			row[title] = value;

		}
		else
		{
			XMLElement* child = ele->FirstChildElement();
			if (child) {
				if (is_xml_arr(child)) {
					row[title] = json::array();
					xml_arr(child, row[title]);
				}
				else {
					xml_obj(child, row, arr_name);
				}
			}
		}

		const XMLAttribute* attirbute = ele->FirstAttribute();
		while (attirbute != NULL)
		{
			row[attirbute->Name()] = attirbute->Value();
			attirbute = attirbute->Next();
		}
		data.push_back(row);
		ele = ele->NextSiblingElement();
	}
}

json xml_to_json(string& src, std::set<std::string> arr_name)
{
	XMLDocument doc;
	doc.Parse(src.c_str());

	json  root;

	XMLElement* rootElement = doc.RootElement();
	xml_obj(rootElement, root, arr_name);
	
	return root;
}
